package com.titanrise.crm.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.titanrise.crm.common.constants.WaitForStatusConstant;
import com.titanrise.crm.common.enums.LogEffect;
import com.titanrise.crm.common.enums.RoleStatusEnum;
import com.titanrise.crm.common.enums.RootStatusEnum;
import com.titanrise.crm.common.utils.*;
import com.titanrise.crm.controller.root.RootAPIController;
import com.titanrise.crm.dao.RootDao;
import com.titanrise.crm.domain.dto.RoleBelongDto;
import com.titanrise.crm.domain.dto.TradeDto;
import com.titanrise.crm.domain.dto.TradeTableDto;
import com.titanrise.crm.domain.dto.UserDto;
import com.titanrise.crm.domain.model.*;
import com.titanrise.crm.domain.vo.ClientSalesRelationShipsVo;
import com.titanrise.crm.domain.vo.SysLoginLogVo;
import com.titanrise.crm.environment.annotation.Autowired;
import com.titanrise.crm.environment.annotation.Service;
import com.titanrise.crm.environment.menu.action.Action;
import com.titanrise.crm.environment.ioc.SingletonPoolUtil;
import com.titanrise.crm.exception.*;
import com.titanrise.crm.handler.RootServicePrinter;
import com.titanrise.crm.service.RootService;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Description:
 * @Author: pront
 * @Time:2024-11-08 08:35
 */
@Service("rootService")
public class RootServiceImpl implements RootService {

    @Autowired
    private RootDao rootDao;

    private final  Function<String, Either<String, String>> checker = IOUtil.getGenericChecker();


//    缓存
    private static Map<Integer, UserDto> memberMap = new HashMap<>();

    private static Map<Integer, TradeDto> tradeMap = new HashMap<>();


    @Override
    public List<UserDto> showAllMembers() {
//        控制台等待查询
        Thread waitThread = IOUtil.waitForSelective(WaitForStatusConstant.SELECT);
        List<UserDto> list = rootDao.selectAllMemberInfForRoot();
        memberMap.clear();
//        构建缓存
        for (int i = 0; i < list.size(); i++) memberMap.put(i + 1, list.get(i));
        waitThread.interrupt();
        return list;
    }


    /**
     * 根据序号删除人员
     */
    @Override
    public Action deleteSalesperson() {
        Connection conn = null;
        try {
            conn = ProjectUtil.getConnection();
            System.out.println("请输入成员的序号:");
            String input = IOUtil.inputLine();
            if (!NumberUtil.isInteger(input)) throw new InputFormatErrorException();
            int no = Integer.parseInt(input);
            if (ObjectUtil.isEmpty(memberMap.get(no))) throw new NotFindInfoException();
            UserDto userDto = memberMap.get(no);
            String uid = userDto.getId();
            Thread thread = IOUtil.waitForSelective(WaitForStatusConstant.DELETE);
            Optional.ofNullable(rootDao.selectAllRelativeUserForSalesId(uid)).ifPresent(list -> {
//                修改与之关联的客户批量状态
                List<String> clientIds = list.stream()
                        .map(User::getId)
                        .peek(System.out::println)
                        .collect(Collectors.toList());
                clientIds.forEach(id -> rootDao.updateClientNonBelongById(id));
            });
//            删除对应关系 与 账户信息
            if (rootDao.deleteRelationshipsForSalesId(uid) != 1 && rootDao.deleteUserInfoByUid(uid) != 1)
                throw new SystemErrorException();
            thread.interrupt();
            conn.commit();

        } catch (InputFormatErrorException | NotFindInfoException e) {
            Console.println(e.getMessage() + "!", LogEffect.RED, LogEffect.BOLD);
            deleteSalesperson();
        } catch (SystemErrorException | SQLException e) {
            Optional.ofNullable(conn).ifPresent(connection -> {
                try {
                    connection.rollback();
                } catch (SQLException ex) {
                    throw new RuntimeException(ex);
                }
            });
            Console.println(e.getMessage() + "!", LogEffect.RED, LogEffect.BOLD);
            deleteSalesperson();
        }
        return Action.JUMP_TO_FUNCTION("/root", RootStatusEnum.MANAGE_MEMBER_INF.getCode());
    }

    @Override
    public List<TradeDto> showAllTrades() {
        Thread waitThread = IOUtil.waitForSelective(WaitForStatusConstant.SELECT);
        List<TradeDto> tradeList = rootDao.selectAllTradesForRoot();
        waitThread.interrupt();
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            Console.println(e.getMessage() + "!", LogEffect.RED, LogEffect.BOLD);
        }
        return tradeList;
    }

    @Override
    public Action deleteTrade() {
        try {
            System.out.println("请输入删除的序号:");
            String input = IOUtil.inputLine();
            if(!NumberUtil.isInteger(input)) throw new InputFormatErrorException();
            int no = Integer.parseInt(input);
            if(ObjectUtil.isEmpty(tradeMap.get(no))) throw new NotFindInfoException();
            Thread waitThread = IOUtil.waitForSelective(WaitForStatusConstant.DELETE);
            int count = rootDao.deleteTradeInfoByTradeId(tradeMap.get(no).getTradeId());
            if(count != 1) throw new SystemErrorException();
            waitThread.interrupt();
            return Action.JUMP_TO_FUNCTION("/root", RootStatusEnum.MANAGE_TRADE_INF.getCode());
        } catch (InputFormatErrorException | NotFindInfoException | SystemErrorException e) {
            Console.println(e.getMessage() + "!", LogEffect.RED, LogEffect.BOLD);
            deleteTrade();
        }
        return null;
    }

    @Override
    public List<SysLoginLog> sysLoginLog(int timeLine, int page) {
        List<SysLoginLog> SysLoginList = null;
        try {
            Thread waitThread = IOUtil.waitForSelective(WaitForStatusConstant.SELECT);
            SysLoginList = rootDao.selectLogInfo(timeLine, page);
            waitThread.interrupt();
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Console.println(e.getMessage() + "!", LogEffect.RED, LogEffect.BOLD);
        }
        return SysLoginList;
    }

    @Override
    public int sysLoginLogCount(int timeLine) {
        return rootDao.selectLogInfoCount(timeLine);
    }

    @Override
    public void showSysLoginLogs(List<SysLoginLog> sysLoginLogs) {
        System.out.println("|  日志ID  |  登入时间  |  登出时间  |  登录设备IP  |  登录状态  |  用户ID  |  用户姓名 |");
        sysLoginLogs.stream().map(log -> {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            String loginTimeStr = log.getLoginTime().format(formatter);
            String logoutTimeStr = Optional.ofNullable(log.getLogoutTime()).map(s -> s.format(formatter)).orElse("null");
            SysLoginLogVo sysLoginLogVo = SysLoginLogVo.builder()
                    .loginTimeStr(loginTimeStr).
                    logoutTimeStr(logoutTimeStr).build();
            BeanUtil.copyProperties(log, sysLoginLogVo);
            return sysLoginLogVo;
        }).forEach(log ->{
            System.out.print( "  |  " + log.getLogId() + "  |  ");
            System.out.print(log.getLoginTimeStr() + "  |  ");
            System.out.print(log.getLogoutTimeStr() +"  |  ");
            System.out.print(log.getIpAddress() + "  |  ");
            System.out.print(log.getLoginStatus() + "  |  ");
            System.out.print(log.getUserId() + "  |  ");
            System.out.print(log.getName() + "  |  ");
            System.out.println();
        });
    }

    @Override
    public Action showSalespersonOfClient() {
//        TODO 分页
        try {
            Thread waitThread = IOUtil.waitForSelective(WaitForStatusConstant.SELECT);
            List<ClientSalesRelationships> list = rootDao.showSalespersonOfClient();

            List<ClientSalesRelationShipsVo>ClientSalesRelationShipList = list.stream().map(clientSales -> {
                String salesId = clientSales.getSalesId();
                String clientId = clientSales.getClientId();
                String clientName = rootDao.selectNameByUid(clientId);
                String salesName = rootDao.selectNameByUid(salesId);
                return new ClientSalesRelationShipsVo(clientName, salesName);
            }).collect(Collectors.toList());
            waitThread.interrupt();
            Thread.sleep(100);

//        打印
            System.out.println("|  客户姓名  |  销售人员姓名  |");
            ClientSalesRelationShipList.forEach(clientSales -> {
                System.out.print("  |  " + clientSales.getClientName() + "  |  ");
                System.out.print(clientSales.getSalesName() + "  |  ");
                System.out.println();
            });
        } catch (InterruptedException e) {
            Console.println(e.getMessage() + "!", LogEffect.RED, LogEffect.BOLD);
        }
        return Action.JUMP_TO_MENU("/root/api/manageClientInfo");
    }

    @Override
    public Action sendMsgToSalesperson() {
//        查询所有销售
        try {
            Thread waitThread = IOUtil.waitForSelective(WaitForStatusConstant.SELECT);
            List<Role> salespersons = rootDao.selectSalesperson();
            waitThread.interrupt();
            Thread.sleep(100);
            System.out.println("销售id    |    销售人员姓名");
            salespersons.forEach(salesperson -> {
                System.out.println(salesperson.getUid() + "    |    " + salesperson.getName());
            });

            String id = ProjectUtil.getLine("请输入销售id：",checker);
            int count = rootDao.selectRoleByUid(id);
            if(count != 1) throw new NotFindInfoException();
            String content = ProjectUtil.getLine("请输入消息内容：", checker);
            waitThread = IOUtil.waitForSelective(WaitForStatusConstant.SEND);
            Messages message = Messages.builder().messageId(ProjectUtil.generateUUID())
                    .content(content)
                    .receiverId(id)
                    .senderId("u1").build();
            count = rootDao.sendMessage(message);
            if(count != 1) throw new SystemErrorException();
            waitThread.interrupt();
            Thread.sleep(150);
            return Action.JUMP_TO_MENU("/root/api/manageClientInfo");
        } catch (SystemErrorException | NotFindInfoException | InterruptedException e) {
            Console.println(e.getMessage() + "!", LogEffect.RED, LogEffect.BOLD);
            sendMsgToSalesperson();
        }
        return null;
    }

    @Override
    public Action distributeClient() {
        Connection connection = null;
        try {
            Thread waitThread = IOUtil.waitForSelective(WaitForStatusConstant.SELECT);
            List<RoleBelongDto> notBelongClients = rootDao.getNotBelongClient();
            if(notBelongClients.size() == 0){
                waitThread.interrupt();
                Thread.sleep(100);
                Console.println("暂无待分配客户!", LogEffect.YELLOW, LogEffect.BOLD, LogEffect.ITALIC);
                return Action.JUMP_TO_MENU("/root/api/manageClientInfo");
            }
            List<Role> roles = rootDao.selectSalesperson();
            waitThread.interrupt();
            Thread.sleep(100);

            RootServicePrinter.distributeClientPrint(notBelongClients, roles);
            String clientUid = ProjectUtil.getLine("请输入客户id：", checker);
            if(rootDao.selectRoleByUid(clientUid) != 1) throw new NotFindInfoException();
            String salespersonUid = ProjectUtil.getLine("请输入销售id：", checker);
            if(rootDao.selectRoleByUid(salespersonUid) != 1) throw new NotFindInfoException();
            waitThread = IOUtil.waitForSelective(WaitForStatusConstant.RESULT);
            connection = ProjectUtil.getConnection();
            int count1 = rootDao.updateNotBelongClient(clientUid);
            ClientSalesRelationships clientSalesRelationships = ClientSalesRelationships.builder()
                    .clientId(clientUid)
                    .salesId(salespersonUid)
                    .id(ProjectUtil.generateUUID()).build();
            int count2 = rootDao.insertOneRelationship(clientSalesRelationships);
            if(count1 != 1 && count2 != 1) throw new SystemErrorException();
            connection.commit();
            waitThread.interrupt();
            Thread.sleep(200);
        } catch (SQLException e) {
            if (ObjectUtil.isNotNull(connection)) {
                try {
                    connection.rollback();
                } catch (SQLException ex) {
                    throw new RuntimeException(ex);
                }
            }
            e.printStackTrace();
        } catch (InterruptedException | NotFindInfoException | SystemErrorException e) {
            Console.println(e.getMessage() + "!", LogEffect.RED, LogEffect.BOLD);
        }
        return Action.JUMP_TO_MENU("/root/api/manageClientInfo");
    }

    @Override
    public Action tradeTable() {
        try {
            Thread waitThread = IOUtil.waitForSelective(WaitForStatusConstant.SELECT);
            List<TradeTableDto> tradeTableDtos = rootDao.selectTradeTable();
            waitThread.interrupt();
            Thread.sleep(150);
            if (tradeTableDtos.isEmpty()) {
                Console.println("暂时还没有业绩情况" + "!", LogEffect.YELLOW, LogEffect.BOLD);
                return Action.JUMP_TO_MENU("/root/api/manageTradeInfo");
            }
            System.out.println("  |  姓名  |  成交订单数  |  合计金额  |" );
            tradeTableDtos.forEach(tradeTableDto -> {
                System.out.println("  |  " + tradeTableDto.getName() + "  |  " + tradeTableDto.getTotalOrders() + "  |  " + tradeTableDto.getTotalSalesPrice() + "  |  ");
            });
        } catch (InterruptedException e) {
            Console.println(e.getMessage() + "!", LogEffect.RED, LogEffect.BOLD);
        }
        return Action.JUMP_TO_MENU("/root/api/manageTradeInfo");
    }

    @Override
    public Action exportTradeData() throws InterruptedException {
        Thread waitThread = IOUtil.waitForSelective(WaitForStatusConstant.RESULT);

        try {
            List<TradeDto> tradeDataList = Optional.ofNullable(rootDao.selectAllTradesForRoot()).orElse(new ArrayList<>());
            String filePath = "export/trade_data.CSV";
            File exportFile = new File(filePath);
            if (!exportFile.getParentFile().exists()) exportFile.getParentFile().mkdirs();

            try (BufferedWriter writer = new BufferedWriter(new FileWriter(exportFile))) {
                writer.write("Trade ID | Salesperson Name | Client Name | Goods Name | Price | Finish Date | Note | Status Message | Number");
                writer.newLine();
                writer.write("---------------------------------------------------------------------------------------------");
                writer.newLine();
                // 写入
                for (TradeDto trade : tradeDataList) {
                    writer.write(String.format("%s | %s | %s | %s | %.2f | %s | %s | %s | %d",
                            trade.getTradeId(),
                            trade.getSalespersonName(),
                            trade.getClientName(),
                            trade.getGoodsName(),
                            trade.getPrice(),
                            trade.getFinishDate().toString(),
                            trade.getNote(),
                            trade.getStatusMsg(),
                            trade.getNumber()));
                    writer.newLine();
                }
                waitThread.interrupt();
                Thread.sleep(150);
                System.out.println("交易数据导出成功，文件路径: " + filePath);
            } catch (IOException e) {
                Console.println("写入导出文件时出错!", LogEffect.RED, LogEffect.BOLD);
            }

        } catch (Exception e) {
            Console.println("导出交易数据时出错!", LogEffect.RED, LogEffect.BOLD);
        }
        // 返回菜单
        return Action.JUMP_TO_MENU("/root/api/manageTradeInfo");
    }


    /**
     * 添加销售人员信息
     */
    @Override
    public Action addSalesperson() {
        Connection connection = null;
        try {
            connection = ProjectUtil.getConnection();
            String username = ProjectUtil.getLine("请输入销售人员账号:", checker);
            String password = ProjectUtil.getLine("请输入密码(包含大小写特殊字符且不少于8位):", checker);
            if (!ValidateUtil.passwordValid(password) || !ValidateUtil.usernameValid(username, memberMap))
                throw new UsnaOrPassInValidException();

            String name = ProjectUtil.getLine("请输入销售人员姓名：", checker);
            String uid = ProjectUtil.generateUUID();
            User user = User.builder()
                    .id(uid)
                    .createTime(LocalDateTime.now())
                    .build();

            String roleId = ProjectUtil.generateUUID();
            Role role = Role.builder()
                    .id(roleId)
                    .uid(uid)
                    .username(username)
                    .password(password)
                    .createTime(LocalDateTime.now())
                    .name(name)
                    .role(RoleStatusEnum.SALESPERSON.getStatus())
                    .build();
            Thread waitThread = IOUtil.waitForSelective(WaitForStatusConstant.INSERT);
            int count = rootDao.addSalesPersonInfo(user, role);
            System.out.println();
            if (count != 1) throw new SystemErrorException();
            connection.commit();
            waitThread.interrupt();

        } catch (UsnaOrPassInValidException | SystemErrorException e) {
            Console.println(e.getMessage() + "!", LogEffect.RED, LogEffect.BOLD);
            addSalesperson();
        } catch (SQLException e) {
            if (ObjectUtil.isNotNull(connection)) {
                try {
                    connection.rollback();
                } catch (SQLException ex) {
                    throw new RuntimeException(ex);
                }
            }
            e.printStackTrace();
            addSalesperson();
        }
        return Action.JUMP_TO_FUNCTION("/root", RootStatusEnum.MANAGE_MEMBER_INF.getCode());
    }

    /**
     * 更新用户信息
     */
    @Override
    public Action updateUsnaPasByNo() {
        try {
            String str = ProjectUtil.getLine("请输入被修改者的序号:", checker);
            if (!NumberUtil.isInteger(str)) throw new InputFormatErrorException();

            int no = Integer.parseInt(str);
            UserDto userDto = memberMap.get(no);
            if (ObjectUtil.isEmpty(userDto)) throw new NotFindInfoException();
            String username = ProjectUtil.getLine("请输入最新的账号:", checker);
            String password = ProjectUtil.getLine("请输入最新的密码(大小写字母与特殊字符且长度不小于8位):", checker);
//            用户名与原来不一致且与其他用户名重复 || 密码错误
            if ((!username.equals(userDto.getUsername()) && !ValidateUtil.usernameValid(username, memberMap))
                    || !ValidateUtil.passwordValid(password))
                throw new UsnaOrPassInValidException();

            String id = userDto.getId();
            Thread waitThread = IOUtil.waitForSelective(WaitForStatusConstant.UPDATE);
//                更新tb_role
            rootDao.updateRoleUsePasByUid(username, password, id);
            waitThread.interrupt();
            Thread.sleep(200);  // 保证主线程后执行
            return Action.JUMP_TO_FUNCTION("/root", RootStatusEnum.MANAGE_MEMBER_INF.getCode());
        } catch (UsnaOrPassInValidException | InputFormatErrorException | NotFindInfoException e) {
            Console.println(e.getMessage() + "!", LogEffect.RED, LogEffect.BOLD);
            updateUsnaPasByNo();
        } catch (Exception e) {
            Console.println(e.getMessage() + "!", LogEffect.RED, LogEffect.BOLD);
            return Action.JUMP_TO_MENU("/root");
        }
        return null;
    }

    private RootAPIController getRootController() {
        return SingletonPoolUtil.getBean(RootAPIController.class);
    }

}
